<script lang="ts" setup>
import { useSystemStore } from '~/stores/system'

interface IProps {
  visible: boolean
  table?: string
  title: string
  createable: boolean
}

interface Column {
  field: string
  type?: string
}

interface IState {
  tableName: string
  columns: Column[]
}

const { t } = useI18n()
const deleted = ref<any[]>([])

const syStore = useSystemStore()

const props = withDefaults(defineProps<IProps>(), {
  table: () => ''
})

const emit = defineEmits(['update:visible', 'commit'])

const display = computed({
  get: () => props.visible,
  set: (value: boolean) => {
    emit('update:visible', value)
    if (!value) {
      resetForm()
    }
  }
})

const state = reactive<IState>({
  tableName: '',
  columns: [
    {
      field: '',
      type: undefined
    }
  ]
})

let backupColumns: string[] = []
const columnTypes = useGetColumnTypes({ immediate: true })
const tableColumns = useGetTableColumns({})
const fixedTableHandler = useFixedTable({})

const validateColumn = (rule: any, _: string, callback: Function) => {
  const index = Number(rule.field.split('_')[1])
  const column = state.columns[index]
  
  if (!column.field.trim()) {
    return callback(new Error(t('please_enter_field_name')))
  }
  if (!column.type) {
    return callback(new Error(t('please_select_field_type')))
  }
  callback()
}

const rules = computed(() => ({
  tableName: [{ required: true, message: t('please_enter_table_name'), trigger: 'blur' }],
  ...state.columns.reduce((acc: any, _, index) => {
    acc[`field_${index}`] = [{ validator: validateColumn, trigger: ['blur', 'change'] }]
    return acc
  }, {}) 
}))

watch(() => props.table, (newTable) => {
  state.tableName = newTable
  tableColumns.refresh({ table: newTable })
})

watch(() => tableColumns.data, (columns: Column[]) => {
  backupColumns = columns.map((k: any) => k.field)
  state.columns = [...columns]
})

const formRef = ref<any>(null)

const submitForm = () => {
  formRef.value.validate((isValid: boolean) => {
    if (isValid) {
      const renames: any = {}
      const exclude = syStore.excludeKeys
      const currentFields = columns.value.map((k) => k.field)
      const originalFields = backupColumns.filter((k: any) => !exclude.includes(k))

      originalFields.forEach((originalField, index) => {
        const currentField = currentFields[index]
        const isDeleted = deleted.value.some((col: any) => col.field === originalField)
        if (currentField && originalField !== currentField && !isDeleted) {
          renames[originalField] = currentField
        }
      })
      const params = formatParams(toRaw(state))
      fixedTableHandler.refresh({
        renames,
        ...params
      })
      resetForm()
      emit('commit')
    }
  })
}

const formatParams = (data: IState) => ({
  table: data.tableName,
  cols: data.columns.reduce((acc: any, column) => {
    acc[column.field] = column.type
    return acc
  }, {})
})

const addColumn = () => {
  state.columns.push({ field: '', type: undefined })
}

const removeColumn = (field: string) => {
  const columnIndex = state.columns.findIndex((col) => col.field === field)
  if (columnIndex !== -1) {
    deleted.value.push(state.columns[columnIndex])
    state.columns.splice(columnIndex, 1)
  }
}

const resetForm = () => {
  formRef.value.resetFields()
}

const disabled = computed(() => {
  return !props.createable
})

const columns = computed(() => {
  const exclude = syStore.excludeKeys
  return state.columns.filter((k: any) => !exclude.includes(k.field))
})

const has = (name: string) => {
  const data = tableColumns.data || []
  const exclude = syStore.excludeKeys
  const keys = data.filter((k: any) => !exclude.includes(k.field))
    .map((k: any) => k.field)
  return keys.includes(name)
}

</script>

<template>
  <Dialog v-model:visible="display" :title="props.title" @commit="submitForm">
    <div class="form-container">
      <div class="form-tools">
        <Button @click="addColumn" icon="plus">
          {{ $t('add_field') }}
        </Button>
      </div>
      <el-form :model="state" :label-width="48" :rules="rules" ref="formRef" @submit.native.prevent>
        <el-form-item :label="$t('table_name')" prop="tableName">
          <el-input :disabled="disabled" v-model="state.tableName" :placeholder="$t('please_enter_table_name')" />
        </el-form-item>
        <el-form-item
          v-for="(column, index) in columns"
          :key="index"
          :label="$t('field_name')"
          :prop="`field_${index}`"
          class="fields"
        >
          <el-input v-model="column.field" :placeholder="$t('please_enter_field_name')">
            <template #prepend>
              <el-select
                v-model="column.type"
                style="width: 200px"
                :disabled="disabled && has(column.field)"
                :placeholder="$t('please_select_field_type')"
              >
                <el-option v-for="field in columnTypes.data" :label="field" :value="field" />
              </el-select>
            </template>
            <template #append>
              <ConfirmTip @ok="removeColumn(column.field)">
                <SVGIcon type="del" />
              </ConfirmTip>
            </template>
          </el-input>
        </el-form-item>
      </el-form>
    </div>
  </Dialog>
</template>

<style lang="scss" scoped>
.form-container {
  padding: 16px 0;
}

.form-tools {
  margin-bottom: 16px;
}
</style>
